/***********************************************************************************
  * File:			bh1750.c
  * Version:		V1.0
  * Date:			2021.5.26
  * Description:	bh1750光照度传感器应用函数接口
***********************************************************************************/

/* 头文件 */
#include "bh1750.h"


/* 函数声明 */
void I2C_BH1750_GPIOConfig(void);
void i2c_Delay(void);
void i2c_Start(void);
void i2c_Stop(void);
void i2c_SendByte(uint8_t _ucByte);
uint8_t i2c_ReadByte(void);
uint8_t i2c_WaitAck(void);
void i2c_Ack(void);
void i2c_NAck(void);
void I2C_BH1750_GPIOConfig(void);
uint8_t i2c_CheckDevice(uint8_t _Address);
uint8_t BH1750_Byte_Write(uint8_t data);
uint16_t BH1750_Read_Measure(void);
void BH1750_Power_ON(void);
void BH1750_Power_OFF(void);
void BH1750_RESET(void);
uint8_t BH1750_Init(void);
float LIght_Intensity(void);

/**
 * @brief:	I2C总线位延迟，最快400KHz。
 * @param:	void。
 * @return:	void。
 */
void i2c_Delay(void)
{
	rt_hw_us_delay(2);
	// uint8_t i;

	// /*　
	//  	下面的时间是通过逻辑分析仪测试得到的。
    //     工作条件：CPU主频72MHz ，MDK编译环境，1级优化
  
	// 	循环次数为10时，SCL频率 = 205KHz 
	// 	循环次数为7时，SCL频率 = 347KHz， SCL高电平时间1.5us，SCL低电平时间2.87us 
	//  	循环次数为5时，SCL频率 = 421KHz， SCL高电平时间1.25us，SCL低电平时间2.375us 
	// */
	// for (i = 0; i < 10; i++);
}

/**
 * @brief:	CPU发起I2C总线启动信号。
 * @param:	void。
 * @return:	void。
 */
void i2c_Start(void)
{
	/* 当SCL高电平时，SDA出现一个下跳沿表示I2C总线启动信号 */
	BH1750_I2C_SDA_1();
	BH1750_I2C_SCL_1();
	i2c_Delay();
	BH1750_I2C_SDA_0();
	i2c_Delay();
	BH1750_I2C_SCL_0();
	i2c_Delay();
}

/**
 * @brief:	CPU发起I2C总线停止信号。
 * @param:	void。
 * @return:	void。
 */
void i2c_Stop(void)
{
	/* 当SCL高电平时，SDA出现一个上跳沿表示I2C总线停止信号 */
	BH1750_I2C_SDA_0();
	BH1750_I2C_SCL_1();
	i2c_Delay();
	BH1750_I2C_SDA_1();
}

/**
 * @brief:	CPU向I2C总线设备发送8bit数据。
 * @param:	_ucByte ： 等待发送的字节。
 * @return:	void。
 */
void i2c_SendByte(uint8_t _ucByte)
{
	uint8_t i;

	/* 先发送字节的高位bit7 */
	for (i = 0; i < 8; i++)
	{		
		if (_ucByte & 0x80)
		{
			BH1750_I2C_SDA_1();
		}
		else
		{
			BH1750_I2C_SDA_0();
		}
		i2c_Delay();
		BH1750_I2C_SCL_1();
		i2c_Delay();	
		BH1750_I2C_SCL_0();
		if (i == 7)
		{
			 BH1750_I2C_SDA_1(); // 释放总线
		}
		_ucByte <<= 1;	/* 左移一个bit */
		i2c_Delay();
	}
}

/**
 * @brief:	CPU从I2C总线设备读取8bit数据。
 * @param:	void。
 * @return:	读到的数据。
 */
uint8_t i2c_ReadByte(void)
{
	uint8_t i;
	uint8_t value;

	/* 读到第1个bit为数据的bit7 */
	value = 0;
	for (i = 0; i < 8; i++)
	{
		value <<= 1;
		BH1750_I2C_SCL_1();
		i2c_Delay();
		if (BH1750_I2C_SDA_READ())
		{
			value++;
		}
		BH1750_I2C_SCL_0();
		i2c_Delay();
	}
	return value;
}

/**
 * @brief:	CPU产生一个时钟，并读取器件的ACK应答信号。
 * @param:	void。
 * @return:	返回0表示正确应答，1表示无器件响应。
 */
uint8_t i2c_WaitAck(void)
{
	uint8_t re;

	BH1750_I2C_SDA_1();	/* CPU释放SDA总线 */
	i2c_Delay();
	BH1750_I2C_SCL_1();		/* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
	i2c_Delay();
	if (BH1750_I2C_SDA_READ())	/* CPU读取SDA口线状态 */
		re = 1;
	else
		re = 0;
	BH1750_I2C_SCL_0();
	i2c_Delay();
	return re;
}

/**
 * @brief:	CPU产生一个ACK信号。
 * @param:	void。
 * @return:	void。
 */
void i2c_Ack(void)
{
	BH1750_I2C_SDA_0();	/* CPU驱动SDA = 0 */
	i2c_Delay();
	BH1750_I2C_SCL_1();	/* CPU产生1个时钟 */
	i2c_Delay();
	BH1750_I2C_SCL_0();
	i2c_Delay();
	BH1750_I2C_SDA_1();	/* CPU释放SDA总线 */
}

/**
 * @brief:	CPU产生1个NACK信号。
 * @param:	void。
 * @return:	void。
 */
void i2c_NAck(void)
{
	BH1750_I2C_SDA_1();	/* CPU驱动SDA = 1 */
	i2c_Delay();
	BH1750_I2C_SCL_1();	/* CPU产生1个时钟 */
	i2c_Delay();
	BH1750_I2C_SCL_0();
	i2c_Delay();	
}

/**
 * @brief:	配置I2C总线的GPIO，采用模拟IO的方式实现。
 * @param:	void。
 * @return:	void。
 */
void I2C_BH1750_GPIOConfig(void)
{
	GPIO_InitType GPIO_InitStructure;

	RCC_EnableAPB2PeriphClk(BH1750_RCC_I2C_PORT, ENABLE);  /* ??GPIO??? */

	GPIO_InitStructure.Pin = BH1750_I2C_SCL_PIN | BH1750_I2C_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	/* ?????? */
	GPIO_InitPeripheral(BH1750_GPIO_PORT_I2C, &GPIO_InitStructure);

	/* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */
	i2c_Stop();
}

/**
 * @brief:	检测I2C总线设备，CPU向发送设备地址，然后读取设备应答来判断该设备是否存在。
 * @param:	_Address：设备的I2C总线地址。
 * @return:	0 表示正确， 返回1表示未探测到。
 */
uint8_t i2c_CheckDevice(uint8_t _Address)
{
	uint8_t ucAck;
	i2c_Start();		/* 发送启动信号 */
	/* 发送设备地址+读写控制bit（0 = w， 1 = r) bit7 先传 */
	i2c_SendByte(_Address | BH1750_I2C_WR);
	ucAck = i2c_WaitAck();	/* 检测设备的ACK应答 */

	i2c_Stop();			/* 发送停止信号 */

	return ucAck;
}

/**
 * @brief:	BH1750写一个字节
 * @param:	void。
 * @return:	成功：0, 失败：非0
 */
uint8_t BH1750_Byte_Write(uint8_t data)
{
	i2c_Start();
	//发送写地址
	i2c_SendByte(BH1750_Addr|0);
	if(i2c_WaitAck()==1)
		return 1;
	//发送控制命令
	i2c_SendByte(data);
	if(i2c_WaitAck()==1)
		return 2;
	i2c_Stop();
	return 0;
}

/**
 * @brief:	BH1750读取测量数据。
 * @param:	void。
 * @return:	成功：返回光照强度 	失败：返回0。
 */
uint16_t BH1750_Read_Measure(void)
{
	uint16_t receive_data=0; 
	i2c_Start();
	//发送读地址
	i2c_SendByte(BH1750_Addr|1);
	if(i2c_WaitAck()==1)
		return 0;
	//读取高八位
	receive_data=i2c_ReadByte();
	i2c_Ack();
	//读取低八位
	receive_data=(receive_data<<8)+i2c_ReadByte();
	i2c_NAck();
	i2c_Stop();
	return receive_data;	//返回读取到的数据
}


/**
 * @brief:	BH1750上电。
 * @param:	void。
 * @return:	void。
 */
void BH1750_Power_ON(void)
{
	BH1750_Byte_Write(POWER_ON);
}

/**
 * @brief:	BH1750s断电。
 * @param:	void。
 * @return:	void。
 */
void BH1750_Power_OFF(void)
{
	BH1750_Byte_Write(POWER_OFF);
}

/**
 * @brief:	BH1750复位。
 * @param:	void。
 * @return:	void。
 */
void BH1750_RESET(void)
{
	BH1750_Byte_Write(MODULE_RESET);
}

/**
 * @brief:	BH1750初始化。
 * @param:	void。
 * @return:	成功：0, 失败：非0。
 */
uint8_t BH1750_Init(void)
{
	I2C_BH1750_GPIOConfig();		/* 配置GPIO */
	
	BH1750_Power_ON();	//BH1750s上电
	//BH1750_RESET();			//BH1750复位
	return BH1750_Byte_Write(Measure_Mode);
	//SysTick_Delay_ms(120);
}

/**
 * @brief:	获取光照强度。
 * @param:	void。
 * @return:	光照强度数据。
 */
float LIght_Intensity(void)
{
	return (float)(BH1750_Read_Measure()/1.1f*Resolurtion);
}
/*********************************************END OF FILE**********************/
